﻿#region Opis pliku
//-----------------------------------------------------------------------------
// Camera.cs
// Autor: Jan Czarnowski
// 11.11.2012
//-----------------------------------------------------------------------------
#endregion

#region Using...

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Collections.Generic;
using System;

#endregion

namespace pogra
{
    /// <summary>
    /// Klasa reprezentująca widok gracza - kamerę
    /// </summary>
    public class Camera : GameComponent
    {
        #region pola

        float _zoom;
        float _rotation;
        Matrix _transform;
        Vector2 _pos;

        #endregion

        #region wlasciwosci

        /// <summary>
        /// Aktualny zbliżenie kamery
        /// </summary>
        public float Zoom
        {
            get { return _zoom; }
            set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; }
        }

        /// <summary>
        /// Aktualny obrót kamery
        /// </summary>
        public float Rotation
        {
            get { return _rotation; }
            set { _rotation = value; }
        }

        /// <summary>
        /// Aktualna pozycja kamery
        /// </summary>
        public Vector2 Pos
        {
            get { return _pos; }
            set { _pos = value; }
        }

        #endregion

        #region inicjalizacja

        /// <summary>
        /// Tworzy nowy obiekt typu Camera
        /// </summary>
        /// <param name="game">Gra, z która związana jest kamera</param>
        public Camera(Game game) : base(game)
        {
            _zoom = 1.0f;
            _rotation = 0.0f;
            _pos = Vector2.Zero;
        }

        #endregion

        #region update

        /// <summary>
        /// Aktualizacja pól kamery. Może znajdować się tu logika 
        /// sterująca jej ruchem (np. inercja)
        /// </summary>
        /// <param name="gameTime">Czas, który upłynął od ostatniego wywołania update</param>
        public override void Update(GameTime gameTime)
        {

        }

        #endregion

        #region metody publiczne

        /// <summary>
        /// Zwróć macierz transformacji reprezentująca aktualny stan kamery
        /// </summary>
        /// <param name="graphicsDevice"></param>
        /// <returns></returns>
        public Matrix GetTransformation(GraphicsDevice graphicsDevice)
        {
            Rectangle viewport = Game.GraphicsDevice.Viewport.Bounds;

            _transform =
                Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
                                            Matrix.CreateTranslation(new Vector3(-viewport.Width/2, -viewport.Height/2, 0)) *
                                            Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
                                            Matrix.CreateTranslation(new Vector3(viewport.Width/2, viewport.Height/2, 0)); 
                                             
            
            return _transform;
        }

        /// <summary>
        /// Zresetuj widok kamery
        /// </summary>
        public void Reset()
        {
            _zoom = 1.0f;
            _rotation = 0.0f;
            _pos = Vector2.Zero;
        }
        
        /// <summary>
        /// Odwrotne przekształcenie punktu
        /// </summary>
        /// <param name="point">Punkt do przeksztalcenia</param>
        /// <param name="graphicsDevice"></param>
        /// <returns></returns>
        public Point transformPoint(Point point, GraphicsDevice graphicsDevice)
        {
            Vector2 tpoint = Vector2.Transform(new Vector2(point.X, point.Y), Matrix.Invert(GetTransformation(graphicsDevice)));

            return new Point((int)tpoint.X, (int)tpoint.Y);
        }

        /// <summary>
        /// Zmiana przybliżenia kamery z uwzględnieniem pozycji myszki
        /// na ekranie.
        /// </summary>
        /// <param name="amount">O ile zmienić zoom</param>
        /// <param name="mousePos">Pozycja myszki</param>
        public void changeZoom(float amount, Point mousePos)
        {
            Rectangle viewport = Game.GraphicsDevice.Viewport.Bounds;
            float newzoom = _zoom + amount;

            float msx = mousePos.X - viewport.Width / 2;
            float msy = mousePos.Y - viewport.Height / 2;

            float width = _pos.X + msx;
            float height = _pos.Y + msy;

            _pos.X -= width * (1 - newzoom / _zoom);
            _pos.Y -= height * (1 - newzoom / _zoom);

            _zoom = newzoom;

            if (_zoom < 0.1f) _zoom = 0.1f;
        }

        #endregion
    }
}
